package com.aisino.api.util;

import org.bouncycastle.crypto.digests.SM3Digest;
import org.bouncycastle.util.encoders.Hex;

import java.nio.charset.StandardCharsets;
import java.util.Map;
import java.util.TreeMap;
import java.util.UUID;

/**
 * SM3签名工具类
 * @author zhenzhoul
 * @date 2025/08/01
 */
public class SM3SignatureUtil {

    /**
     * 生成SM3签名
     * @param params 包含签名参数的Map
     * @param appSecret 应用密钥
     * @return 签名值
     */
    public static String generateSignature(Map<String, String> params, String appSecret) {
        // 创建新的TreeMap以保证排序
        TreeMap<String, String> sortedParams = new TreeMap<>(params);

        // 添加appSecret到参数中
        sortedParams.put("appSecret", appSecret);

        // 构建待签名字符串
        StringBuilder signStr = new StringBuilder();
        for (Map.Entry<String, String> entry : sortedParams.entrySet()) {
            if (signStr.length() > 0) {
                signStr.append("&");
            }
            signStr.append(escapeSpecialChars(entry.getKey())).append("=").append(escapeSpecialChars(entry.getValue()));
        }
//        log.info("待签名字符串: " + signStr);
        return sm3Digest(signStr.toString());
    }

    /**
     * 对特殊字符进行转义处理
     *
     * @param str 待处理的字符串
     * @return 转义后的字符串
     */
    private static String escapeSpecialChars(String str) {
        return str.replace("=", "%3D")
                .replace("&", "%26")
                .replace(" ", "%20")
                .replace("\n", "%0A")
                .replace("\r", "%0D");
    }

    /**
     * 执行SM3摘要计算
     *
     * @param data 待摘要的数据
     * @return 十六进制格式的摘要结果
     */
    private static String sm3Digest(String data) {
        byte[] input = data.getBytes(StandardCharsets.UTF_8);
        SM3Digest digest = new SM3Digest();
        digest.update(input, 0, input.length);
        byte[] hash = new byte[digest.getDigestSize()];
        digest.doFinal(hash, 0);
        return Hex.toHexString(hash);
    }

    /**
     * 验证签名
     *
     * @param params 参数Map
     * @param appSecret 应用密钥
     * @param signature 待验证的签名
     * @return 签名是否有效
     */
    public static boolean verifySignature(Map<String, String> params, String appSecret, String signature) {
        String generatedSignature = generateSignature(params, appSecret);
        return generatedSignature.equalsIgnoreCase(signature);
    }
}